/* Pouziva knihovnu https://github.com/adafruit/DHT-sensor-library.git
 * knihovna (adresar) se musi prejmenovat na DHT
 * dokumentace k teplotnimu cidlu
 * http://www.adafruit.com/datasheets/DHT22.pdf
 */
#include "DHT.h"

#define TEPLOTA_MIN 16.0 //stupne celsia, pod tuto teplotu se zapne topeni
#define TOPIT_JAK_DLOUHO 60000ul //milisekundy (60000 = 1minuta), po te se topeni vypne a zase se zmeri teplota
#define INTERVAL_OPAKOVANI 20000ul //milisekundy, jak dlouho cekat mezi ctenim teplot

#define PIN_DHT 2     // digitalni pin pro vystup z DHT22 teplomer a vlhkost
#define PIN_POHYB 3
#define INT_POHYB 1 //interrupt pro pin 3
#define PIN_RELE 8
#define PIN_LED_CERVENA 22 //topilo se byla tam zima
#define PIN_LED_ZELENA 38 //byl tam nejaky pohyb
#define PIN_LED_BILA 52 //status led
#define PIN_TLACITKO_RESET 6
#define DHTTYPE DHT22   // DHT 22  (AM2302)

/*
Kalibracni tabulka teplot. Skutecna vs. DHT220
17.2 ~ 18.4
*/
#define KALIBRACE -1.2f

void pin_change_pohyb();

// Initialize DHT sensor for normal 16mhz Arduino
DHT dht(PIN_DHT, DHTTYPE);

float h,t,f,hi; //vlhkost, teplotaC, teplotaF, vlhkostni index
unsigned long cas_topeni_start = 0;
boolean topeni_bezi = false;
boolean byl_pohyb = false;

void setup() {
  Serial.begin(9600);

  //teplomer
  Serial.println("DHT220 init");
  dht.begin();

  //motion detector
  pinMode(PIN_POHYB, INPUT);
  attachInterrupt(INT_POHYB, pin_change_pohyb, RISING);

  //rele na topeni
  pinMode(PIN_RELE, OUTPUT);
  digitalWrite(PIN_RELE, LOW);

  //tlacitko reset
  pinMode(PIN_TLACITKO_RESET, INPUT);
  digitalWrite(PIN_TLACITKO_RESET, HIGH); // turn on pullup resistors

  //LEDky
  pinMode(PIN_LED_CERVENA, OUTPUT);
  pinMode(PIN_LED_ZELENA, OUTPUT);
  pinMode(PIN_LED_BILA, OUTPUT);

  //ukaz pri resetu, ze LEDky funguji
  digitalWrite(PIN_LED_CERVENA, HIGH);
  digitalWrite(PIN_LED_ZELENA, HIGH);
  digitalWrite(PIN_LED_BILA, HIGH);
  delay(500);
  digitalWrite(PIN_LED_CERVENA, LOW);
  digitalWrite(PIN_LED_ZELENA, LOW);
  digitalWrite(PIN_LED_BILA, LOW);

}

void readTemp(){
  // Reading temperature or humidity takes about 250 milliseconds!
  h = dht.readHumidity();
  // Read temperature as Celsius
  t = dht.readTemperature() + KALIBRACE;
  f = dht.readTemperature(true);

  // Check if any reads failed and exit early (to try again).
  if (isnan(h) || isnan(t) || isnan(f)) {
    Serial.println("Failed to read from DHT sensor!");
    return;
  }

  // Compute heat index
  // Must send in temp in Fahrenheit!
  hi = dht.computeHeatIndex(f, h);
}

void reset() {
  digitalWrite(PIN_LED_CERVENA, LOW);
  digitalWrite(PIN_LED_ZELENA, LOW);
  digitalWrite(PIN_RELE, LOW);
  byl_pohyb = false;
}

void zapni_topeni() {
  if (topeni_bezi == false) { //zmena stavu
    topeni_bezi = true;
    digitalWrite(PIN_RELE, HIGH);
    cas_topeni_start = millis();
    digitalWrite(PIN_LED_CERVENA, HIGH);
    Serial.print(millis());
    Serial.println("\tZapinam topeni");
  }
}
void vypni_topeni() {
  digitalWrite(PIN_RELE, LOW);

  if (topeni_bezi == true) { //zmena stavu
    topeni_bezi = false;
    cas_topeni_start = millis();
    Serial.print(millis());
    Serial.println("\tVypinam topeni");
  }
}

void log_status() {
  Serial.print(millis());
  Serial.print("\ttep:");
  Serial.print(t);
  Serial.print("*C\t");

  Serial.print("Vlh: ");
  Serial.print(h);
  Serial.print("%\t");
  Serial.print("HI:");
  Serial.print(hi);
  Serial.print("*F");
  if (byl_pohyb == true)
    Serial.print("\tPOHYB");
  Serial.println();

  int po_peti = floor(t / 5);
  int po_jednom = floor(t - (po_peti * 5));

  for (int i = 0; i < po_peti; i++) {
    digitalWrite(PIN_LED_BILA, HIGH);
    delay(500);
    digitalWrite(PIN_LED_BILA, LOW);
    delay(100);
  }

  for (int i = 0; i < po_jednom; i++) {
    digitalWrite(PIN_LED_BILA, HIGH);
    delay(100);
    digitalWrite(PIN_LED_BILA, LOW);
    delay(100);
  }
}

void loop() {

  //reset stavu diod
  if (digitalRead(PIN_TLACITKO_RESET) == LOW) {
    reset();
  }

  //teplota a topeni
  readTemp();
  boolean top = false;
  if (t < TEPLOTA_MIN) {
    top = true;
    // Serial.println("top=true");
  }
  if ((topeni_bezi == true) && (cas_topeni_start + TOPIT_JAK_DLOUHO < millis())) { //uplynul interval doby topeni
    top = false;
    // Serial.print("vyp ");    Serial.println(cas_topeni_start + TOPIT_JAK_DLOUHO);
  }
  if (millis() < (2 * INTERVAL_OPAKOVANI)) {
    top = false;
    Serial.print(millis());
    Serial.print("\tcas < ");
    Serial.print(2 * INTERVAL_OPAKOVANI);
    Serial.println("\tBud je cerstve zapnuto nebo pretekl cas po 50 dnech");
  }

  if (top == true)
    zapni_topeni();
  else
    vypni_topeni();

  //motion detector
  // if (digitalRead(PIN_POHYB) == HIGH || byl_pohyb == true) {
    // digitalWrite(PIN_LED_ZELENA, HIGH);
  // }

  log_status();

  delay(INTERVAL_OPAKOVANI);

}

void pin_change_pohyb() {
  byl_pohyb = true;
  digitalWrite(PIN_LED_ZELENA, HIGH);
}
